package org.dei.perla.parser;

import java.io.BufferedReader;
import java.io.StringReader;
import java.util.ArrayList;

import org.dei.perla.parser.grammar.*;
import org.dei.perla.parser.statements.*;
import org.dei.perla.utils.pipe.*;
import org.dei.perla.utils.waiter.Waitable;
import org.dei.perla.utils.waiter.Waiter;

public class QueryParserAgent extends Thread {
	private static boolean firstTime = true;
	private static String errorLog = null;
	private static QueryParserAgent agent = null;
	private static Pipe<Query> queryPipe = null;
	
	private Waiter<Pipe<String>> queryWaiter = null;

	private QueryParserAgent(){
		if(errorLog == null){
			errorLog = new String();
		}
		if(queryPipe == null){
			queryPipe = new Pipe<Query>("QueryParsed");
		}
			
	}
	
	public static QueryParserAgent getDefault() {
		if(agent == null)
			agent = new QueryParserAgent();
		return agent;
	}

	public synchronized ArrayList<Query> parse(String query) {
		ArrayList<Query> queryList = null;
		StringReader reader = new StringReader(query);
		BufferedReader bufferedReader = new BufferedReader(reader);
		if(firstTime){
			firstTime = false;
			new Parser(bufferedReader);
		}
		else{
			Parser.ReInit(bufferedReader);
		}
		try {
			queryList = Parser.StatementSequence();
			QueryParserAgent.setErrorLog("Parsing success");
			errorLog.notifyAll();
		} catch (ParseException e) {
			QueryParserAgent.setErrorLog(e.getMessage());
			e.printStackTrace();
			return null;
		}
		return queryList;
	}

	public void setQueryToParsePipe(Pipe<String> pipe){
		queryWaiter = new Waiter<Pipe<String>>();
		queryWaiter.start();
		queryWaiter.addWaitable(pipe.getWaitable());
	}
	
	public static Pipe<Query> getQueryPipe(){
		return queryPipe;
	}
	
	public synchronized static void setErrorLog(String error){
		errorLog = new String(error);
	}
	
	
	public synchronized static String getErrorLog() {
		return errorLog;
	}

	public void run() {
		Waitable<Pipe<String>> waitable;
		String toParse;

		while(true) {
			waitable = queryWaiter.waitNext();
			toParse = waitable.getParentComponent().dequeue();
			if (toParse != null) {
				ArrayList<Query> queryList = parse(toParse);
				for(Query queryItem: queryList)
					queryPipe.enqueue(queryItem);
					
			} else {
				// Killpacket ricevuto, chiudo la connessione con il DB,
				// termino le pipe, termino il processo
				queryWaiter.removeWaitable(waitable);
				waitable.getParentComponent().stop();
				queryWaiter.stop();
				//TODO rivedere questo punto
				break;
			}
		}
	}
	
}
